#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdio.h>
#include <netdb.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <mpi.h>
#include "crawler_lib.h"

#define BUFFER_SIZE 4096
#define FILENAME_LENGTH 1000
//#define DEBUG

extern int errno;


int main (int argc, char **argv)
{
	int my_rank = 0;
	int ret = 0;
	int size = 0;
	int aux = 0;
	int aux2 = 0;
	int sd; //socket descriptor
	struct hostent *hp;
	struct sockaddr_in server; //structura folosita pentru conectare
	int port = 80; //portul de comunicatie (80 - HTTP)
	char * maskFile = "urls.txt";
	char * urlFile = (char *)malloc(FILENAME_LENGTH);
	struct URLList * listaUrl = 
		(struct URLList *)malloc(sizeof(struct URLList));
	struct URLList * nod = (struct URLList *)malloc(sizeof(struct URLList));
	
	FILE *stream,* prop_file, * link_file; 
	/*Numele fisierului inc are se va salva info de pe site*/
	char * url_file = (char *)malloc(FILENAME_LENGTH);
	
	char * buffer = (char*)malloc(BUFFER_SIZE);
	/*Numele curent al fisierului de propozitii*/
	char * prop_filename = (char *)malloc(FILENAME_LENGTH);
	/*Numele curent al fisierului de link-uri */
	char * link_filename= (char *)malloc(FILENAME_LENGTH);
	/*host = www.ceva.ro*/
	char * host = (char *)malloc(FILENAME_LENGTH);
	/* Inititalizarea MPI*/
	ret= MPI_Init(&argc, &argv);
	
	ret= MPI_Comm_size( MPI_COMM_WORLD, &size );
	
	ret= MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
	
	
	/*Un scurt test*/
	printf("{%d}[%d of %d]\n",my_rank,my_rank, size);

	/*Fiecare nod are fisierul lui URL-uri*/
	sprintf(urlFile,"%d%s",my_rank,maskFile);

	/*Citesc fisierul de URL-uri si le pun in lista*/
#ifdef DEBUG
	printf("{%d} Citesc fisierul de configurare: %s\n", my_rank, urlFile);
#endif
	ret = readFile(urlFile,listaUrl);
	if (ret)
	{
		perror("Eroare la citirea fisierului de configurare\n");
		MPI_Finalize();
		return errno;
	}
	
	
	nod = listaUrl;

	if (nod == NULL)
	{
		/*Lista URL este goala*/
		MPI_Finalize();
		return 0;
		
	}

while(nod)
{
	// crearea socketului
	sd = socket(AF_INET, SOCK_STREAM,0);
	if (sd == -1)
	{
		perror("Eroare la creare socket\n");
		MPI_Finalize();
		return errno;
	}
	
	
	url_file = normalizez_nume_fisier(nod->url);
	link_filename = denumeste_link_file(url_file, my_rank);
	prop_filename = denumeste_prop_file(url_file, my_rank);
	
	stream = fopen(url_file,"w");
	link_file = fopen(link_filename,"w");
	prop_file = fopen(prop_filename,"w");
	
	if (stream == NULL)
	{
		perror("Eroare la creare fisier\n");
		MPI_Finalize();
		return errno;
	}

	

	host = extrageHostDinURL(nod->url);
	hp = gethostbyname(host);

	if( hp == NULL )
	{

	  perror("Eroare la gethostbyname\n");
	  MPI_Finalize();
	  return errno;
          
  	}

	//umplem structura folosita pentru realizarea conexiunii cu serverul
	bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
	server.sin_family = AF_INET;
	server.sin_port = htons(port);
	
//#ifdef DEBUG
	printf("{%d}[Connect...%s:%d]\n",my_rank,host,server.sin_port);
//#endif	
	
	ret = connect ( sd, (struct sockaddr *) &server, sizeof (struct sockaddr) );
	
	if ( ret == -1 )
	{
		perror("Eroare la connect()");
		MPI_Finalize();
		return errno;
	} 
	else
	{
#ifdef DEBUG
		printf("{%d}[Connected...]\n",my_rank);
#endif
	}
	
	/*Cream HTTP request*/
	memset(buffer,0,BUFFER_SIZE);
	sprintf(buffer,"GET %s HTTP/1.1\n", nod->url);
	

#ifdef DEBUG
	printf("{%d}[Scriu...][%s]\n",my_rank,buffer);
#endif	
	
	ret = write(sd, buffer,strlen(buffer));
	
	if (ret <= 0 )
	{
		perror("Eroare la trimitere GET");
		close(sd);
		MPI_Finalize();
		return errno;
	}
	
	memset(buffer,0,BUFFER_SIZE);
	sprintf(buffer,"Host: %s\n\n",nod->url);

#ifdef DEBUG	
	printf("{%d}[Scriu...][%s]\n", my_rank, buffer);
#endif

	ret = write(sd, buffer,strlen(buffer));
	if (ret <= 0 )
	{
		perror("Eroare la trimitere Host");
		close(sd);
		MPI_Finalize();
		return errno;
	}
	
#ifdef DEBUG
	printf("{%d}[Am scris...]\n", my_rank);
#endif	

	

#ifdef DEBUG
	printf("{%d}[Citesc...]\n",my_rank);
#endif
	ret = 1;
	
			
	while ( ( ret != 0 ) )
	{
		aux++;
		memset(buffer,0,BUFFER_SIZE);
		ret = read(sd, buffer, BUFFER_SIZE-1);
		if ( ret == -1)
		{
			printf( "{%d} Eroare la citirea de pe socket", my_rank);
			break;
		}
		/*Pot aparea probleme cand  dupa  simbolul % apare un simbol pe care fprintf incearca sa-l interpreteze ca in %s, %d, etc... 
		fprintf ignora spatiile dintre % si aceste litere*/
		replaceChars(buffer,'%','_');
		parse_buffer(buffer, link_file, prop_file);
		aux2 = fprintf(stream, buffer);
		if( aux2 == -1 )
			printf( "{%d} Eroare la scrierea in fisierul url", my_rank);
		
			
	}
	
	

	
	
	fclose(stream);
	fclose(link_file);
	fclose(prop_file);
	close(sd);
	
	
	
	
	printf("{%d} Am citit site-ul: %s. \n", my_rank, nod->url);
	nod = nod->next;
}

	free(buffer);
	printf("{%d} Am terminat. \n", my_rank);

	MPI_Finalize();
	return 0;

}
